package com.sunday.common.core.remoting.base.response;

import com.sunday.common.core.enums.InnerErrorCodeEnum;
import com.sunday.common.core.remoting.base.response.core.ExceptionResolve;
import com.sunday.common.core.remoting.base.response.core.MethodCallback;
import com.sunday.common.core.remoting.base.response.core.ThrowableFilter;
import com.sunday.common.core.remoting.rest.response.RestResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.Nullable;

import java.util.Optional;

/**
 * 异常处理器
 *
 * @author zsy
 * @see org.springframework.util.ReflectionUtils
 * @see org.springframework.aop.aspectj.annotation.ReflectiveAspectJAdvisorFactory
 * @since 2022/10/14
 */
@Slf4j
public class ResponseHandler {

    /**
     * 执行方法，转换缺省错误
     *
     * @param callback
     * @param resolve
     * @return {@link T}
     */
    public static <T> T invoke(MethodCallback<T> callback, ExceptionResolve<T> resolve) {
        return invoke(callback, resolve, null);
    }

    /**
     * 执行方法，转换缺省错误
     *
     * @param callback 执行方法回调
     * @param resolve  异常处理
     * @param filter   异常拦截
     * @return {@link T}
     */
    public static <T> T invoke(MethodCallback<T> callback, ExceptionResolve<T> resolve, @Nullable ThrowableFilter filter) {
        assert callback != null : "callback must not be null";
        assert resolve != null : "resolve must not be null";
        try {
            return callback.doWith();
        } catch (Throwable e) {
            return resolve.resolve(Optional.ofNullable(filter).orElse(ThrowableFilter.DEFAULT_FILTER), e);
        }
    }

    /**
     * 是否为结果未知
     * 全平台将 C0_001 调用第三方服务出错， 作为统一的结果提示
     * 结果未知可能存在补偿策略，使结果保持最终一致性
     *
     * @param response
     * @return {@link boolean}
     */
    public static boolean isUnknown(Response response) {
        return Optional.ofNullable(response)
                .filter(Response::isFailure)
                // C0_001(ErrorClassifyEnum.C + "0001","调用第三方服务出错"),
                .map(res -> InnerErrorCodeEnum.C0_001.errorCode.equals(res.getErrorCode()))
                .orElse(false);
    }

    /**
     * 是否为结果未知
     *
     * @param restResponse
     * @return {@link boolean}
     */
    public static boolean isUnknown(RestResponse restResponse) {
        return Optional.ofNullable(restResponse)
                .filter(RestResponse::isFailure)
                // C0_001(ErrorClassifyEnum.C + "0001","调用第三方服务出错"),
                .map(res -> InnerErrorCodeEnum.C0_001.errorCode.equals(res.getErrorCode()))
                .orElse(false);
    }

}
